package com.lwc.backendsinglestructure.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 */
@EnableAsync
@Configuration
public class ThreadPoolConfig {
   

    @Bean("CommonThreadPoolExecutor")
    public Executor syncExecutor() {
   
        // 获取可用处理器的Java虚拟机的数量
        int sum = Runtime.getRuntime().availableProcessors();
        System.out.println("系统最大线程数 -> " + sum);

        // 实例化自定义线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        // 设置线程池中的核心线程数(最小线程数)
        // 线程池的核心线程数指的是线程池中一直存在的线程数量，即使它们没有任务可执行，处于空闲状态。
        // 如果线程池中的线程数小于核心线程数，则创建新线程来处理任务，即使其他空闲线程可用。
        // 如果线程池中的线程数已经等于核心线程数，那么新的任务就会被放入任务队列等待执行
        executor.setCorePoolSize(16);

        // 设置线程池中的最大线程数
        // 如果线程池中的线程数已经达到了核心线程数，并且任务队列已满，则创建新线程来处理任务。
        // 如果线程池中的线程数等于最大线程数，则任务将被拒绝。
        executor.setMaxPoolSize(64);

        // 设置线程池中任务队列的容量
        // 线程池中的任务队列用于存储还未被执行的任务，当线程池中的线程已经全部被占用时，新的任务会被放入任务队列中等待执行。如果任务队列已满，那么新的任务就会被拒绝执行。
        executor.setQueueCapacity(500);

        // 设置线程池中空闲线程的存活时间
        // 当线程池中的某个线程执行完任务后，如果当前线程池中的线程数大于核心线程数，那么这个空闲线程就会被放入线程池的等待队列中。
        // 在等待队列中的空闲线程，如果在`keepAliveSeconds`时间内没有被再次使用，就会被回收销毁，以释放系统资源。如果`keepAliveSeconds`设置为0，则表示空闲线程立即被回收销毁。
        executor.setKeepAliveSeconds(60);

        // 设置线程池中线程的名称前缀
        // 线程池中的每个线程都有一个唯一的名称，这个名称通常是由线程池的名称和线程的编号组成的。使用`setThreadNamePrefix()`方法可以在默认的线程名前面添加一个前缀，以便更好地区分不同的线程池。
        executor.setThreadNamePrefix("async-");

        // 设置线程池关闭时等待所有任务完成的时间。
        // 当调用executor.shutdown()方法关闭线程池时，线程池会等待一段时间，如果在这段时间内所有任务都完成了，线程池会正常关闭；如果还有任务没有完成，线程池将强制关闭，未完成的任务将被丢弃。
        executor.setAwaitTerminationSeconds(60);

        // 设置线程池中任务队列已满时的拒绝策略，当线程池中的任务队列已满，而且线程池中的线程已经达到了最大线程数时，新的任务就无法被执行。这时就需要设置拒绝策略来处理这种情况。
        // setRejectedExecutionHandler()方法提供了几种拒绝策略，包括：
        // 1. AbortPolicy：直接抛出RejectedExecutionException异常，阻止系统正常运行。
        // 2. CallerRunsPolicy：只要线程池未关闭，该策略直接在调用者线程中，运行当前被丢弃的任务。
        // 3. DiscardOldestPolicy：丢弃队列里最老的一个任务，并执行当前任务。
        // 4. DiscardPolicy：不处理，直接丢弃掉当前任务。
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());

        // 设置线程池在关闭时是否等待所有任务完成
        // 如果设置为`true`，则在调用`shutdown()`方法时，线程池会等待所有已提交的任务执行完毕后再关闭。
        // 如果设置为`false`，则在调用`shutdown()`方法时，线程池会立即关闭，未执行的任务将被丢弃。
        executor.setWaitForTasksToCompleteOnShutdown(true);

        // 链路日志ID
        executor.setTaskDecorator(new MdcTaskDecorator());
        // 初始化线程池的配置
        executor.initialize();

        return executor;
    }
}
